NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name [CCP] Billing & Inventory Services for Printavo & Online Labels v2 // @namespace CCP // @include https://www.printavo.com/* // @include https://secure.onlinelabels.com/Account/OrderHistory.aspx // @include https://www.onlinelabels.com/products/* // @require http://code.jquery.com/jquery-3.4.1.min.js // @resource customCSS https://fitaf570.com/jqui/ui-lightness.css // @require https://code.jquery.com/ui/1.12.0/jquery-ui.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js // @downloadURL https://openuserjs.org/install/macheteYeti/[CCP]_Billing_Inventory_Services_for_Printavo_Online_Labels_v2.user.js // @updateURL https://openuserjs.org/install/macheteYeti/[CCP]_Billing_Inventory_Services_for_Printavo_Online_Labels_v2.user.js // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_getValue // @grant GM_setValue // @license MIT // @author macheteYeti // @description Adds functionality to Printavo & OnlineLabels to enable stock management features. // @version 40 // ==/UserScript== $(document).ready(function(){ user=localStorage.getItem('CCPuser'); shop=localStorage.getItem('CCPshop'); //determine whether using Online Labels or Printav var plat='ol'; if(window.location.href.indexOf("printavo")>-1)plat='pa'; //specify statuses which should trigger an inventory update var include=['Ready for Pickup','Delivery','Ship','In Production']; //serve different code based on which platform is in use switch(plat){ case 'ol': if(user=='reception')return false; if(window.location.href.indexOf('products')>-1){ //if on a product page, determine if we've passed ordering parameters var urlParams = new URLSearchParams(window.location.search); if(typeof urlParams.get('qty')!=typeof undefined&&urlParams.get('qty')!=null&&urlParams.get('qty').length>0){ //fill in order quantty $('.v-pob__custom-quantity-input').val(urlParams.get('qty')); setTimeout(()=>{ //add to cart $('.v-pob__add-to-cart')[0].click(); setTimeout(()=>{ //if this is the last item to order, go to cart, otherwise close the page if(urlParams.get('last')==null)window.close(); else window.location.href='https://secure.onlinelabels.com/Cart/ViewCart.aspx'; },1500); },1500); } } else{ //if we're not on a product page, we know we're on the order history page due to distinct @includes //gather up visible invoices var foundInvoices=[]; $('a[href*=OrderDetails]').each(function(){ foundInvoices.push($(this).attr('href').split('?')[1]); }); //check if we've tracked visible invoices $.ajax({type:'GET',url:'https://fitaf570.com/ccp/getStock.php',async:false,dataType:'json',data:{type:'invoices',foundInvoices:foundInvoices},fail:function(jqXHR,textStatus,errorThrown){console.log('Could not get invoices, server response: '+textStatus+': '+errorThrown);},success:function(d){ var tracked='<a class="c-button c-button--secondary c-button--full u-margin-bottom--tiny inventoryTracking tracked">Inventory Tracked!</a>'; var untracked='<a class="ss-duplicate-order c-button c-button--full u-margin-bottom--tiny inventoryTracking" style="">Track Inventory (Now)</a><a class="ss-duplicate-order c-button c-button--full u-margin-bottom--tiny inventoryTracking threeDays">Track Inventory<br>(In 3 Days)</a>'; $('.p-order-box').each(function(){ //for each order, based on if we find the invoice ID, put out the relevant buttons if($.inArray($(this).find('a[href*=OrderDetails]').attr('href').split('?')[1],d.inv)>-1)$(tracked).prependTo($(this).find('.p-order-box__totals>div').first()); else $(untracked).prependTo($(this).find('.p-order-box__totals>div').first()); }) }}); $(document).on('click','.inventoryTracking:not(.tracked)',function(){ //when clicking an inventory button, gather the details var orig=$(this); var data={'type':'stockChange','action':'add','inv':$(this).parents('.p-order-box').find('a[href*=OrderDetails]').attr('href').split('?')[1]}; if($(this).hasClass('threeDays'))data['when']='interval'; else data['when']='now'; //gather the products $(this).parents('.p-order-box').find('.u-border--top.u-large-text-align--left').find('.row.align-middle').each(function(){ vals=[$(this).find('div').first().next().find('div').first().next().contents().text().trim().trimLeft()]; $.each($(this).find('div').first().next().text().replaceAll("\n\n","\n").split("\n"),function(i,v){ if(v.indexOf('Sheets')>-1)vals.push(v.trim().trimLeft().replace("Sheets","").trim().trimLeft()); }); data['vals']=vals; //send the data $.ajax({type:'GET',url:'https://fitaf570.com/ccp/getStock.php',async:false,dataType:'json',data:data}); }); //hide the recording buttons $(orig).parent().find('.inventoryTracking').fadeOut(); }); } break; case 'pa': //if we don't already have a generic inventory utilization button, add it to the top nav if($('#genericRecord').length==0)$('.nav.navbar-nav').prepend('<li><a class="menu-item" title="Record Supply Usage" id="genericRecord"><img width="16" height="16" class="new-item__icon" src="https://djqnomyzwkbyb.cloudfront.net/assets/app/icon-new@2x-074c3957e49b442a12334ec6132993212f3e9a0241a52251f6b9832dc17b2e62.png">Record</a></li>'); //retrieve the products we will use in the autocomplete lookup sku=$.ajax({type:'GET',url:'https://fitaf570.com/ccp/getStock.php',async:false,dataType:'json',data:{type:'sku'},fail:function(jqXHR,textStatus,errorThrown){console.log('Could not get sku, server response: '+textStatus+': '+errorThrown);}}).responseJSON; //instantiate the popup to gather the inventory utilization $('body').append('<div id="inventoryDialog" style="display:none" title="Log Usage"><form autocomplete="off"><input id="inventoryQty" placeholder="Sheets used" autocomplete="off"><br><input id="inventoryLookup" placeholder="Select a Stock"><input type="hidden" id="inventoryJob"></form></div>'); $('#inventoryDialog').dialog({autoOpen:false,width:300,position:{my:'right center',at:'right bottom',of: event}}); //hide the popup initially $('#inventoryDialog').dialog('close'); function openDialog(loc=1,e){ /* loc 1 = calendar loc 2 = generic top nav record loc 3 = forced generic top nav record on invoice page load */ switch(loc){ case 1: $('.jq-order-preview-modal').css('display','block'); $('#inventoryDialog').dialog({appendTo:'.jq-order-preview-modal'}) //set job via url in Printavo popup $('#inventoryJob').val($('.modal-content.modal-calendar .btn.btn-success.pull-left').attr('href').split('/')[2]); break; case 2: //set job via url if(window.location.href.indexOf('/invoices/')>-1)$('#inventoryJob').val(window.location.href.split('/').pop()); $('#inventoryDialog').dialog('open'); break; case 3: //set job via url $('#inventoryJob').val(window.location.href.split('/').pop()); break; } $('#inventoryDialog').dialog("option","position",{my: "right bottom+15", of: e}); // if(user!='reception'&&shop!='kingston')$('#inventoryDialog').dialog('open'); $('#inventoryQty').focus(); } //if someone tries to look up a product before specifying a quantity, we add error styles to the quantity box. when someone starts typing in it, they are removed $(document).on('keydown','#inventoryQty.ui-state-error',function(){ $(this).removeClass('ui-state-error'); }); $('#inventoryLookup').autocomplete({ source:sku, width:200, delay:100, autoFocus:true, focus:function(){$(this).focus();}, select:function(event,ui){ //when we select a stock from the autocomplete list, check that we have specified a quantity if($('#inventoryQty').val().length==0){ $('#inventoryQty').addClass('ui-state-error').effect('shake'); $('#inventoryLookup').val(''); $('#inventoryQty').focus(); return false; } //if a quantity has been specified, gather the rest of the info var dat={type:'stockChange',action:'subtract',val:$('#inventoryQty').val(),id:ui.item.value,user:user,inv:$('#inventoryJob').val()}; // $('#inventoryLookup').val(ui.item.label); //send the record $.ajax({type:'GET',url:'https://fitaf570.com/ccp/getStock.php',async:false,dataType:'json',data:dat,success:function(d){ //once recorded, clear the popup and ready it for another input $('#inventoryDialog form')[0].reset(); $('#inventoryLookup').val('').empty(); $('#inventoryQty').focus(); }}); this.value = ""; return false; } }); if(window.location.href.indexOf('/invoices/')>-1||window.location.href.indexOf('/customers/')>-1){ if(window.location.href.indexOf('/invoices/')>-1){ //if we're on an invoice page, store the hashed work order URL var wo=''; $.each($('.dropdown-menu.pull-right a'),function(i,v){ if($(this).attr('href').indexOf('work_orders')>-1)wo=$(this).attr('href').split('/').pop(); }); $.ajax({type:'GET',url:'https://fitaf570.com/ccp/getStock.php',async:false,dataType:'json',data:{type:'wo',pid:window.location.href.split('/').pop(),wo:wo}}); } //if we're on an invoice page, check if we have recorded inventory usage for it //if not show the popup $.ajax({type:'GET',url:'https://fitaf570.com/ccp/getStock.php',async:false,dataType:'json',data:{type:'checkInvoice',inv:window.location.href.split('/').pop()},success:function(d){ if(!d.inv&&window.location.href.indexOf('/invoices/')>-1)openDialog(3,$('#genericRecord')); }}); async function setPaymentIntent(){ //readLoc 1 = individual invoice 2 = all unbilled on /customers/ 3 = partial payment on /invoices/ 4 = partial payment on /customers/ fetchURL="https://fitaf570.com/ccp/stripe2.php?"; params={'type':'getIntent','invoices':[],ids:[],'due':0,'user':user,'shop':shop,readLoc:readLoc}; if(readLoc==1){ var due=1.0*($('.ref-invoice-wrapper.orders-invoice-wrapper.invoice-layout .well.well__no-border').first().find('.form-control.form-control__disabled-bare').last().text().trim().trimLeft().replace('$','').replaceAll(',','')*100); if(due==0||due==0.0){ let due=prompt("Could not get invoice total. Please input it here."); } params.dues=[due]; params.due+=due; params.invoices.push($('h3.pdf-invoice-number').text().split('#')[1].trim()); params.ids.push(window.location.href.split('/').pop()); } else if(readLoc==3){ params.due=prompt("Enter Partial Payment Amount"); params.due*=100; params.invoices.push($('h3.pdf-invoice-number').text().split('#')[1].trim()); params.ids.push(window.location.href.split('/').pop()); } else if(readLoc==2){ params.dues=[]; $('#orders-index-list tr').each(function(){ if($(this).find('.paid-label').length>0)return true; if($.inArray($(this).find('.status').last().text().trim(),noBillStati)==-1){ var thisTot=$(this).find('td').last().prev().find('.text-muted').text().replace('$','').replaceAll(',','')*100; params.due+=1.0*thisTot; params.dues.push(thisTot); params.ids.push($(this).attr('data-clickable').split('/').pop()); params.invoices.push($(this).find('td').first().clone().children().remove().end().text().trim().trimLeft()); } }); console.log(params); } else if(readLoc==4){ params.dues=[]; $('#new_payment tbody tr').each(function(){ if($(this).find('input').val().length>1){ var thisTot=$(this).find('input').val()*100; params.due+=1.0*thisTot; params.dues.push(thisTot); params.ids.push($(this).find('td').first().find('a').attr('href').split('/').pop()); params.invoices.push($(this).find('td').first().find('a').text().replace('#','')); } }); console.log(params); } $('body').removeClass('loading'); await fetch(fetchURL+$.param(params),{method:"POST"}).then((response)=>{ if(response.status>=400&&response.status<600){ alert("Stripe servers could not be reached. Please restart the card reader. If the problem persists, contact Yeti"); } return response; }).catch((error)=>{ console.log(error); }); } function unexpectedDisconnect(){ //should an auto-reconnect be built here? alert('Lost connection to card reader. Refresh the page and try again.'); $('body').removeClass('loading'); } $('<li class="dropdown-item item"><a class="serveInvoice" data-type="single"><span class="dollar">$</span> Feed Card Reader</a></li><li class="dropdown-item item"><a class="serveInvoice" data-type="partial"><span class="dollar">$</span> Feed Card Reader (Partial)</a></li><li class="divider"></li>').insertAfter($('.invoice__sidebar-ul .dropdown-menu .divider').eq(($('.invoice__sidebar-ul .dropdown-menu .divider').length-4))); if($('.paid-label').length&&window.location.href.indexOf('/invoices/')>-1)$('.serveInvoice').addClass('disabled'); $(document).on('click','.serveInvoice',function(e){ if($(this).hasClass('disabled')){ alert("It appears this invoice is already paid. If you disagree, contact Yeti and provide an invoice ID."); return false; } $('body').addClass('loading'); console.log('feeding reader based on loc'); e.preventDefault(); if($(this).attr('data-type')=='single')readLoc=1; else if($(this).attr('id')=='feedSelected')readLoc=4; else if($(this).attr('data-type')=='partial')readLoc=3; else readLoc=2; setPaymentIntent(); }); if(window.location.href.indexOf('/customers/')>-1){ noBillStati=['Completed','Loss']; $('.modal-footer:not(.readered)').append($('<input value="Feed Card Reader (Selected)" class="btn btn-success pull-right serveInvoice" data-type="multi" id="feedSelected">')); $('.modal-footer').addClass('readered'); $(document).arrive('#new_payment',function(){ $('.modal-footer:not(.readered)').append($('<input value="Feed Card Reader (Selected)" class="btn btn-success pull-right serveInvoice" data-type="multi" id="feedSelected">')); $('.modal-footer').addClass('readered'); }); $('<li><a href="#" class="serveInvoice" data-type="multi">Feed Card Reader (<span id="selectedCount">All</span> Unpaid)</a> <span id="selectedTot"></span></li>').insertAfter($('.sidebar-menu li').last()); } } $(document).on('click','.dropdown-select-status__menu li',function(e){ //when we change status on the calendar, if we are specifying a qualified status, show the popup if($.inArray($(this).text().trim().trimLeft(),include)>-1)openDialog(1,e); }); $(document).on('click','#genericRecord',function(e){ //if we click the generic record button in the top nav, show the popup openDialog(2,e); }); break; default:break; } }); var newCSS = GM_getResourceText ("customCSS"); GM_addStyle (newCSS); GM_addStyle( ` .inventoryTracking{position:absolute;top:0;left:0;width:27%;margin-left:3%} .tracked{cursor:default} .threeDays{left:30%} #inventoryDialog{width:200px;height:200px} .ui-dialog.ui-corner-all.ui-widget.ui-widget-content{z-index:999} #inventoryDialog input{width:150px;margin-bottom:1em} #inventoryQty.ui-state-error::placeholder{color:#fff} #genericRecord{cursor:pointer} .dollar{font:1.4em 'calibri',sans-serif;font-weight:bold;color:#ADB9C0;display:inline-block;margin-right:8px} .serveInvoice{cursor:wait} div[aria-describedby='inventoryDialog']{position:fixed !important} .checker,.serveInvoice{cursor:pointer} body.loading{cursor:progress} body.loading .serveInvoice{cursor:progress !important} .serveInvoice.disabled{cursor:not-allowed !important} #feedSelected{width:250px} ` );